#!/usr/bin/env python3
#
# The purpose of this file is to produce rst output interspersed into
# the the text of the example codes

import sys
import re
import tempfile
import shutil
import io
import pathlib
import pprint

import apsw.ext

from typing import Any, TextIO

input_name, output_name = sys.argv[1:]

# start of each section in example-code.py
section_re = r"""###\s+(?P<section>\b\w+\b):\s+(?P<desc>.*)\s*"""

# magic string from output to recognise new section
section_marker = "!@#$%^&*()(-:"

# start of rst output
header_example = """\
.. Automatically generated by example2rst.py.  Do not edit this file

.. currentmodule:: apsw

Example/Tour
============

This code demonstrates usage of APSW.  It gives you a good overview of
all the things that can be done.  Also included is output so you can
see what gets printed when you run the code.

There are also specific examples in the classes, functions,
and attribute documentation.

.. code-block:: python
"""

header_fts = """\
.. Automatically generated by example2rst.py.  Do not edit this file

.. currentmodule:: apsw

Full Text Search Example/Tour
=============================

You can do FTS5 using normal SQL `as documented
<https://www.sqlite.org/fts5.html>`__.  This example shows using APSW
specific functionality and extras.

.. code-block:: python

"""

header_session = """\
.. Automatically generated by example2rst.py.  Do not edit this file

.. currentmodule:: apsw

Session Example/Tour
====================

This example shows using APSW to create and use the `Session extension
<https://www.sqlite.org/sessionintro.html>`__

.. code-block:: python

"""

header_json = """\
.. Automatically generated by example2rst.py.  Do not edit this file

.. currentmodule:: apsw

JSON Example/Tour
====================

This example shows using `JSON <json.org>`__ with SQLite, and
additional functionality provided by APSW to make it easier to use.

.. code-block:: python

"""


header = {
    "examples/main.py": header_example,
    "examples/fts.py": header_fts,
    "examples/session.py": header_session,
    "examples/json.py": header_json,
}[input_name]


replacements = {
    'pathlib.Path("session.sql")': 'pathlib.Path("doc/_static/samples/session.sql")'
}

def get_output(filename: str):
    code: list[str] = []
    for line in pathlib.Path(filename).read_text().splitlines():
        if line.split() == ["from", "pprint", "import", "pprint"]:
            code.append("# " + line)
            continue
        mo = re.match(section_re, line)
        if mo:
            code.append(f"print('{section_marker}{mo.group('section')}')")
            continue
        for k, v in replacements.items():
            if k in line:
                line = line.replace(k, v)
        code.append(line.rstrip().replace("sys.stdout", "my_io"))

    output: dict[str, list[str]] = {}
    cur_section = None

    my_io = io.StringIO()

    def my_print(*args: Any) -> None:
        nonlocal output, cur_section
        s = " ".join(str(a) for a in args)
        if s.startswith(section_marker):
            v = my_io.getvalue()
            if v:
                my_print(v)
                my_io.seek(0)
                my_io.truncate(0)
            cur_section = s[len(section_marker) :]
            assert cur_section not in output
            output[cur_section] = []
            print("SECTION", cur_section)
            return

        assert cur_section is not None
        output[cur_section].extend(s.split("\n"))

        print(s)

    def my_pprint(obj):
        my_print(pprint.pformat(obj))

    if False:  # make True if you need to debug the changes
        print("\n".join(code))

    exec(compile("\n".join(code), filename, "exec"), {"print": my_print, "pprint": my_pprint, "my_io": my_io})

    return output


def gen_rst(filename: str, outfile: TextIO, output: dict[str, list[str]]) -> None:
    print(header, file=outfile)
    cur_section = None
    seen_blank = True

    with open(filename, "rt") as source:
        for num, line in enumerate(source):
            mo = re.match(section_re, line)
            if mo:
                if cur_section and output[cur_section]:
                    print("\n\n.. code-block:: output\n", file=outfile)
                    for l in output[cur_section]:
                        print("    " + l, file=outfile)
                    print("", file=outfile)
                cur_section = mo.group("section")
                print(f"\n.. index:: {mo.group('desc')} (example code)\n", file=outfile)
                print(f".. _example_{cur_section}:\n", file=outfile)
                print(mo.group("desc"), file=outfile)
                print("-" * len(mo.group("desc")), file=outfile)
                print("", file=outfile)
                seen_blank = False
                continue

            if not seen_blank:
                if not line.strip():
                    seen_blank = True
                    print("\n.. code-block:: python\n", file=outfile)
                else:
                    l = line.rstrip()
                    l = l.lstrip("#")[1:]
                    print(l, file=outfile)
                continue
            print("   " + line.rstrip(), file=outfile)

    f.flush()


if __name__ == "__main__":
    try:
        output = get_output(input_name)
    except:
        apsw.ext.print_augmented_traceback(*sys.exc_info())
        raise
    with tempfile.NamedTemporaryFile("wt", prefix="example2rst") as f:
        gen_rst(input_name, f, output)
        shutil.copy(f.name, output_name)
